package com.github.florent37.library;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.PageSlider;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;

import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * BubbleTab 气泡组件布局
 *
 * @since 2021-04-20
 */
public class BubbleTab extends DirectionalLayout {
    private static final float HALF_INT_VALUE = 0.5f;
    private static final float CIRCLE_SCALE_DEFALUT_RADIO = 1.80f;
    private static final int POST_TASK_DELAY_TIME = 50;
    private Setting mSetting;
    private Circle mCircle;
    private PageSlider mPageSlider;
    private List<Component> mChildComponentList;
    private int mChildCount;
    private int mPageChosenIndex;
    private int mTabWidth;
    private ItemSelectedListener mItemSelectedListener;
    private Context mContext;
    private EventHandler eventHandler;

    public interface ItemSelectedListener {
        /**
         * item selected callback
         *
         * @param index
         * @param isSelected
         */
        void onItemSelected(int index, boolean isSelected);
    }

    PageSlider.PageChangedListener pageChangeListener = new PageSlider.PageChangedListener() {
        @Override
        public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
            if (positionOffsetPixels < 0) {
                // 往回滑动判断
                positionOffset = positionOffset * -1;
            }
            if (mChildCount != 0) {
                mTabWidth = getWidth() / mChildCount;
            }
            float translationX;

            // 当滑动过快，出现position过快跳变问题
            if (position == mPageChosenIndex && Math.abs(positionOffset) == 1) {
                translationX = position * mTabWidth;
            } else {
                translationX = position * mTabWidth + mTabWidth * positionOffset;
            }
            mCircle.setTranslationX(translationX);
            float distanceFromMiddle = 0;
            if (positionOffset > 0) {
                distanceFromMiddle = Math.abs(positionOffset - HALF_INT_VALUE);
            } else {
                distanceFromMiddle = Math.abs(positionOffset + HALF_INT_VALUE);
            }
            float scale = distanceFromMiddle + HALF_INT_VALUE;
            mCircle.setScale(scale);
            setItemSelectedByOffset(position, positionOffset);
            postInvalidate();
        }

        @Override
        public void onPageSlideStateChanged(int state) {
        }

        @Override
        public void onPageChosen(int chosenIndex) {
            mPageChosenIndex = chosenIndex;
            for (int index = 0; index < mChildCount; index++) {
                setItemSelected(index, index == chosenIndex);
            }
        }
    };

    /**
     * BubbleTab constructor
     *
     * @param context
     */
    public BubbleTab(Context context) {
        super(context);
        init(context, null);
    }

    /**
     * BubbleTab constructor
     *
     * @param context
     * @param attrSet
     */
    public BubbleTab(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet);
    }

    /**
     * BubbleTab constructor
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public BubbleTab(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet);
    }


    private void init(Context context, AttrSet attrSet) {
        this.mContext = context;
        mSetting = new Setting(context, attrSet);
        mCircle = new Circle();
        eventHandler = new EventHandler(EventRunner.current());
        addDrawTask(mDrawTask, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
    }

    /**
     * setInit 初始化圆形气泡摆放位置
     *
     * @param selPos
     */
    public void setInit(int selPos) {

        //绘制圆形图标
        getChildView(BubbleTab.this);

        // 先移动到第一个item中心位置
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                initCircleImageState(selPos);
            }
        }, POST_TASK_DELAY_TIME);

    }

    private void postInvalidate() {
        invalidate();
    }

    @Override
    public void arrange(int left, int top, int width, int height) {
        super.arrange(left, top, width, height);
        mChildCount = getChildCount();
    }

    private DrawTask mDrawTask = (component, canvas) -> {
        mCircle.onDraw(canvas);
    };

    private void setItemSelectedByOffset(int position, float positionOffset) {
        if (positionOffset != 0 && Math.abs(positionOffset) != 1) {
            if (positionOffset > 0) {
                if (positionOffset < HALF_INT_VALUE) {
                    setItemSelected(position, true);
                    if (position + 1 < mChildCount) {
                        setItemSelected(position + 1, false);
                    }
                } else {
                    setItemSelected(position, false);
                    if (position + 1 < mChildCount) {
                        setItemSelected(position + 1, true);
                    }
                }
            } else {
                if (Math.abs(positionOffset) < HALF_INT_VALUE) {
                    setItemSelected(position, true);
                    if (position - 1 >= 0) {
                        setItemSelected(position - 1, false);
                    }
                } else {
                    setItemSelected(position, false);
                    if (position - 1 >= 0) {
                        setItemSelected(position - 1, true);
                    }
                }
            }
        }
    }


    private void initCircleImageState(int selPos) {
        if (mCircle != null) {
            updateCircleRatio();
            mCircle.setColor(mSetting.circleColor);
        }

        int curPage = mPageSlider.getCurrentPage();
        int diffPage = selPos - curPage;
        if (curPage == 0 && selPos == 0) {
            setItemSelected(0, true);
        }
        if (diffPage == 0) {
            return;
        }
        for (int j = 0; j < Math.abs(diffPage); j++) {
            if (diffPage > 0) {
                mPageSlider.setCurrentPage(curPage + j + 1);
            } else {
                mPageSlider.setCurrentPage(curPage - j - 1);
            }
        }
    }

    private void updateCircleRatio() {
        int displayHeight = Utils.getDisplayHeightInPx(mContext);
        int displayWidth = Utils.getDisplayWidthInPx(mContext);
        if (displayWidth > displayHeight) {
            float ratio = (float) (new BigDecimal((float) displayWidth / displayHeight).
                setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());
            mSetting.circleRatio = mSetting.originalCircleRatio * ratio;
        } else {
            mSetting.circleRatio = mSetting.originalCircleRatio;
        }
    }

    private int getChildItemWidth() {
        int itemWidth = 0;
        if (mChildCount > 0) {
            int containerWidth = Utils.getDisplayWidthInPx(getContext());
            itemWidth = containerWidth / mChildCount;
        }
        return itemWidth;
    }


    /**
     * setupWithViewPager 传入需绑定的PageSlider
     *
     * @param pageSlider
     */
    public void setupWithPageSlider(PageSlider pageSlider) {
        if (this.mPageSlider != null) {
            this.mPageSlider.removePageChangedListener(pageChangeListener);
        }
        this.mPageSlider = pageSlider;
        this.mPageSlider.addPageChangedListener(pageChangeListener);
    }

    private void getChildView(DirectionalLayout childContainer) {
        mChildCount = childContainer.getChildCount();
        mChildComponentList = new ArrayList<>();
        for (int i = 0; i < mChildCount; i++) {
            int clickIndex = i;
            Component component = childContainer.getComponentAt(i);
            mChildComponentList.add(component);
            component.setClickedListener(new ClickedListener() {
                @Override
                public void onClick(Component component) {
                    int curPage = mPageSlider.getCurrentPage();
                    int diffPage = clickIndex - curPage;
                    if (diffPage == 0) {
                        return;
                    }
                    for (int j = 0; j < Math.abs(diffPage); j++) {
                        if (diffPage > 0) {
                            mPageSlider.setCurrentPage(curPage + j + 1);
                        } else {
                            mPageSlider.setCurrentPage(curPage - j - 1);
                        }
                    }
                    setItemSelected(curPage, false);
                }
            });
        }
    }

    /**
     * setItemSelected 传入需绑定的PageSlider
     *
     * @param i
     * @param selected
     */
    private void setItemSelected(int i, boolean selected) {
        if (mItemSelectedListener != null) {
            mItemSelectedListener.onItemSelected(i, selected);
        }

    }

    /**
     * setOnItemSelectedListener 设置page item页选中接口回调
     *
     * @param listener
     */
    public void setOnItemSelectedListener(ItemSelectedListener listener) {
        this.mItemSelectedListener = listener;
    }

    public List<Component> getItemComponent() {
        return mChildComponentList;
    }


    /**
     * Circle 气泡相关操作方法
     *
     * @since 2021-04-20
     */
    private class Circle {
        private float translationX = 1f;
        private float scale = 1f;
        private static final float HALF_WIDTH_RATIO = 0.5f;
        private static final int CIRCLE_RADIUS_OFFSET = 4;
        private int mViewWidth;
        private Paint mPaint = new Paint();

        public void setWidth(int width) {
            this.mViewWidth = width;
        }

        public int getWidth() {
            return mViewWidth;
        }

        public void setScale(float scale) {
            this.scale = scale;
        }

        public void setColor(Color color) {
            mPaint.setColor(color);
        }

        public Circle() {
            mPaint.setColor(mSetting.circleColor);
            mPaint.setAntiAlias(true);
            mPaint.setStrokeWidth(1);
            mPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
        }

        public void setTranslationX(float translationX) {
            this.translationX = translationX;
        }

        public void onDraw(Canvas canvas) {
            canvas.save();
            canvas.translate(translationX, 0);
            updateCircleRatio();
            int tabWidth;
            if (mChildCount != 0) {
                tabWidth = BubbleTab.this.getWidth() / mChildCount;
            } else {
                tabWidth = BubbleTab.this.getWidth();
            }
            int tabHeight = BubbleTab.this.getHeight();
            canvas.drawCircle(tabWidth * HALF_WIDTH_RATIO, tabHeight * HALF_WIDTH_RATIO,
                tabHeight * HALF_WIDTH_RATIO * scale * mSetting.circleRatio - CIRCLE_RADIUS_OFFSET, mPaint);
            canvas.restore();
        }

    }

    /**
     * Setting 气泡相关的参数
     *
     * @since 2021-04-20
     */
    static class Setting {
        float originalCircleRatio;
        private final Color defaultBorderColor = Color.RED;
        float circleRatio = CIRCLE_SCALE_DEFALUT_RADIO;
        Color circleColor = defaultBorderColor;

        /**
         * Setting constructor
         *
         * @param context
         * @param attrs
         */
        public Setting(Context context, AttrSet attrs) {
            if (attrs != null) {

                circleColor = AttrUtil.getColorValue(attrs, "CustomerDependentLayout_circleColor", defaultBorderColor.toString());
                circleRatio = AttrUtil.getFloatValue(attrs, "CustomerDependentLayout_circleRatio", circleRatio);
            }
            originalCircleRatio = circleRatio;
        }
    }
}
